<template>
  <el-dialog
    :title="title"
    v-model="visible"
    custom-class="video-preview-dialog"
    :style="dialogStyle"
    :width="dialogWidth"
    @closed="onClose"
  >
    <div class="video-container">
      <!-- 加载状态 -->
      <div v-if="isLoading" class="loading-container">
        <el-icon class="is-loading">
          <Loading/>
        </el-icon>
        <span>正在获取视频信息...</span>
      </div>

      <!-- 大文件提示 -->
      <div v-else-if="videoFileSize > 10" class="large-file-container">
        <Icon class="large-file-icon" icon="ep:video-camera"/>
        <div class="large-file-info">
          <div class="file-size">文件大小: {{ formatFileSize(videoFileSize) }}</div>
          <div class="file-name">{{ getFileName(videoUrl) }}</div>
          <div class="file-tip">该视频文件较大，建议下载后观看</div>
          <el-button type="primary" @click="downloadVideo">
            <Icon icon="ep:download"/>
            下载视频
          </el-button>
        </div>
      </div>

      <!-- 视频播放器 -->
      <video
        v-else
        ref="videoRef"
        :src="videoUrl"
        controls
        style="max-height: 70vh; max-width: 100%;"
        @loadedmetadata="onVideoLoad"
      ></video>
    </div>
  </el-dialog>
</template>

<script lang="ts" setup>
import {computed, ref, watch} from 'vue'
import {propTypes} from '@/utils/propTypes'
import {Loading} from "@element-plus/icons-vue";

defineOptions({name: 'VideoPreview'})

const props = defineProps({
  modelValue: propTypes.bool.def(false),
  videoUrl: propTypes.string.def(''),
  title: propTypes.string.def('视频预览'),
  width: propTypes.string.def('70%')
})

const emit = defineEmits(['update:modelValue'])

const visible = ref(props.modelValue)
const videoRef = ref<HTMLVideoElement | null>(null)
const videoWidth = ref(0)
const videoHeight = ref(0)
const aspectRatio = ref(16 / 9) // 默认宽高比
const isLoading = ref(true)
const videoFileSize = ref(0) // 视频文件大小，单位MB

// 格式化文件大小
const formatFileSize = (size: number) => {
  if (size < 1) return '小于1MB'
  return size.toFixed(1) + ' MB'
}

// 从URL获取文件名
const getFileName = (url: string) => {
  if (!url) return '未知文件'
  try {
    const fileName = url.split('/').pop() || '视频文件'
    return decodeURIComponent(fileName)
  } catch (e) {
    return '视频文件'
  }
}

// 下载视频
const downloadVideo = () => {
  if (!props.videoUrl) return

  try {
    const a = document.createElement('a')
    a.href = props.videoUrl
    a.download = getFileName(props.videoUrl)
    document.body.appendChild(a)
    a.click()
    document.body.removeChild(a)
  } catch (e) {
    console.error('下载视频失败:', e)
    window.open(props.videoUrl, '_blank')
  }
}

// 获取视频文件大小
const getVideoFileSize = async (url: string) => {
  isLoading.value = true
  try {
    const response = await fetch(url, {method: 'HEAD'})
    const contentLength = response.headers.get('content-length')
    if (contentLength) {
      videoFileSize.value = parseInt(contentLength) / (1024 * 1024)
    } else {
      videoFileSize.value = 0
    }
  } catch (e) {
    console.warn('无法获取视频大小', e)
    videoFileSize.value = 0
  } finally {
    isLoading.value = false
  }
}

// 计算对话框宽度
const dialogWidth = computed(() => {
  // 获取窗口宽度的80%作为最大宽度
  const maxWidth = window.innerWidth * 0.8
  return videoWidth.value > 0 ?
    `${Math.min(videoWidth.value + 40, maxWidth)}px` : props.width
})

// 计算对话框样式
const dialogStyle = computed(() => {
  if (videoHeight.value > 0) {
    const maxHeight = window.innerHeight * 0.8
    const height = Math.min(videoHeight.value + 100, maxHeight)
    return {
      '--el-dialog-max-height': `${height}px`
    }
  }
  return {}
})

// 视频加载完成后获取尺寸
const onVideoLoad = () => {
  if (videoRef.value) {
    // 获取视频的原始宽高
    videoWidth.value = videoRef.value.videoWidth
    videoHeight.value = videoRef.value.videoHeight
    aspectRatio.value = videoWidth.value / videoHeight.value

    // 调整为合理的显示尺寸
    const maxWidth = window.innerWidth * 0.8
    const maxHeight = window.innerHeight * 0.7

    // 如果视频过大，按比例缩小
    if (videoWidth.value > maxWidth) {
      videoWidth.value = maxWidth
      videoHeight.value = maxWidth / aspectRatio.value
    }

    if (videoHeight.value > maxHeight) {
      videoHeight.value = maxHeight
      videoWidth.value = maxHeight * aspectRatio.value
    }
  }
}

watch(() => props.modelValue, (val) => {
  visible.value = val
  if (val && props.videoUrl) {
    getVideoFileSize(props.videoUrl)
  }
})

watch(() => visible.value, (val) => {
  emit('update:modelValue', val)
})

watch(() => props.videoUrl, (val) => {
  if (val && visible.value) {
    // 当视频URL变化时重置尺寸并获取新视频大小
    videoWidth.value = 0
    videoHeight.value = 0
    getVideoFileSize(val)
  }
})

const onClose = () => {
  if (videoRef.value) {
    videoRef.value.pause()
  }
  emit('update:modelValue', false)
}
</script>

<style lang="scss" scoped>
.video-preview-dialog :deep(.el-dialog__body) {
  display: flex;
  justify-content: center;
  align-items: center;
  padding: 20px;
  overflow: hidden;
}

.video-container {
  display: flex;
  justify-content: center;
  align-items: center;
  width: 100%;
}

.loading-container {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  padding: 30px;

  .el-icon {
    font-size: 24px;
  }
}

.large-file-container {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 30px;
  text-align: center;

  .large-file-icon {
    font-size: 60px;
    color: var(--el-color-info);
    margin-bottom: 20px;
  }

  .large-file-info {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 10px;

    .file-size {
      font-size: 16px;
      font-weight: 500;
    }

    .file-name {
      font-size: 14px;
      color: var(--el-text-color-secondary);
      max-width: 400px;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
    }

    .file-tip {
      margin: 10px 0;
      color: var(--el-text-color-secondary);
    }
  }
}
</style>
